var CHARS_TO_ESCAPE = {
  '#': '\\#',
  '$': '\\$',
  '%': '\\%',
  '^': '\\^{}',
  '&': '\\&',
  '_': '\\_',
  '{': '\\{',
  '}': '\\}',
  '~': '\\tilde',
  '\\': '\\backslash'}

var DOCS_FUNCS = ['\\superscript', '\\subscript', '\\rootof'];
  
// This function adds a menu to the doc so that users can run parseAllEquations
function onOpen() {
  var ui = DocumentApp.getUi();
  // Or DocumentApp or FormApp.
  ui.createMenu('Accessibility')
      .addItem('Math Alt Text', 'parseAllEquations')
      .addToUi();
}

function onInstall(e) {
  onOpen(e);
}

function parseAllEquations() {
  // get Body Content
  var body = DocumentApp.getActiveDocument().getBody();
  
  // Define the search parameters.
  var searchType = DocumentApp.ElementType.EQUATION;
  var searchResult = null;
  
  // Find all equations in the document
  while (searchResult = body.findElement(searchType, searchResult)) {
    var eq = searchResult.getElement().asEquation();
    var out = readEquation(eq);

    var url = 'http://23.251.135.48:8888/mathml/convert?latex=' + encodeURIComponent(out);
    var response = UrlFetchApp.fetch(url);
    var json = response.getContentText();
    var data = JSON.parse(json);

    var altText = searchResult.getElement().getParent().appendText(data.altText);
    altText.setLinkUrl(data.cloudUrl);
    
    Logger.log(out);
    //DocumentApp.getUi().alert(out);
    //UrlFetchApp.fetch();
  }
}

// Takes in a Google Docs text node and escapes it for LaTeX
function escapeText(text) {
  var output = [];
  for (var i = 0; i < text.length; i++) {
    var char = text.charAt(i);
    if (CHARS_TO_ESCAPE[char] !== undefined) {
      char = CHARS_TO_ESCAPE[char];
    }
    output.push(char);
  }
  return output.join('');  
}

// Processes a function node and returns the text for it.
function processFunctionElem(elem) {
  // TODO: Google Docs uses a lot of special functions.  
  // We would either need to add those functions as an add on 
  // to the server's LaTeX parser, or we would need to replace
  // them with a universal solution, as is done below.
  elem = elem.asEquationFunction();
  var code = elem.getCode();
  if (DOCS_FUNCS.indexOf(code) !== -1) {
    var child1 = processElem(elem.getChild(0));
    // child 1 will be a function separator, which we don't care about.
    var child2 = processElem(elem.getChild(2));
  }
  // It should be foo^bar rather than \superscript{foo}{bar}
  if (code === '\\superscript') {
    return child1 + '^{' + child2 + '}';
  // It should be foo_bar rather than \subscript{foo}{bar}
  } else if (code === '\\subscript') {
    return child1 + '_{' + child2 + '}'; 
  // It should be \sqrt[foo]{bar} rather than \rootof{foo}{bar}
  } else if (code === '\\rootof') {
    return '\sqrt[' + child1 + ']{' + child2 + '}';
  // It's a real LaTeX function, so we can just recursively read the equation from it.
  } else {
    return elem.getCode() + '{' + readEquation(elem) + '}';
  }
}

// Returns the text for the given elem node.
function processElem(elem) {
    var type = elem.getType();
    if (type == DocumentApp.ElementType.EQUATION_FUNCTION) {
      return processFunctionElem(elem);
    } else if (type == DocumentApp.ElementType.EQUATION_SYMBOL) {
      elem = elem.asEquationSymbol();
      return elem.getCode();
    } else if (type == DocumentApp.ElementType.TEXT) {
      elem = elem.asText();
      return escapeText(elem.getText());
    } else if (type == DocumentApp.ElementType.EQUATION_FUNCTION_ARGUMENT_SEPARATOR) {
      elem = elem.asEquationFunctionArgumentSeparator();
      return '}{';
    } else {
      Logger.log('ERROR: unknown type.  The type: ' + type);
    }
}

// read all elements in the equation.
// Returns a string with the LaTeX equation.
function readEquation(equation) {
  var combinedText = '';
  var nChildren = equation.getNumChildren();
  for (var i = 0; i < nChildren; i++) {
    var child = equation.getChild(i);
    combinedText += processElem(child);
  }
  return combinedText;
}